package stud.mpgame.flash.game;

import stud.mpgame.flash.map.GameMap;
import stud.mpgame.network.Message;
import stud.mpgame.physics.PhysicsWorld;
import stud.mpgame.physics.Vector2D;
import stud.mpgame.snapshot.IGameObject;
import stud.mpgame.snapshot.ISnapshot;
import stud.mpgame.snapshot.ASnapshot;
import stud.mpgame.snapshot.ICommand;

import stud.mpgame.flash.scene.GameWorldView;

import flash.utils.IDataInput;

import stud.mpgame.flash.game.GameEventDispatcher;

/**
 * ...
 * @author pavel[f.pavel91@gmail.com]
 */
class GameWorld extends ASnapshot {
	
	private var players:Array< Player >;
	
	private var gameEventDispatcher:GameEventDispatcher;
	
	private var physicsWorld:PhysicsWorld;
        
	private var localPlayerID:Int;
	
    public function new() {
		super();	
		this.players = new Array< Player >();
    }
	
	public function init(localPlayerID:Int, gameEventDispatcher:GameEventDispatcher, gameMap:GameMap) {
		this.gameEventDispatcher = gameEventDispatcher;
		this.localPlayerID = localPlayerID;
		this.physicsWorld = new PhysicsWorld(new Vector2D(0, 0.35 * 1e-3), gameMap);
		for (player in players)
			physicsWorld.addCircle(player.getCircle());
	}
	
	public function getPlayers():Array< Player > {
		return players;
	}
	
	public function getLocalPlayer():Player {
		return GameUtils.getPlayerByID(players, localPlayerID);
	}
	
	public override function readExternal(input:IDataInput, owner:Message) {
		super.readExternal(input, owner);
        var playersAmount:Int = input.readInt();
		for (i in 0...playersAmount) {
            var player:Player = new Player();
            player.readExternal(input, owner);
            players.push(player);			
        }
	}
    
	public override function interpolate(deltaTime:Int, serverSnapshot:ISnapshot):Void {
		super.interpolate(deltaTime, serverSnapshot);
		
		//trace("INTERPOLATE");
		
		//this.toString();
		//cast(serverSnapshot, GameWorld).toString();
		/*
		super.interpolate(deltaTime, serverSnapshot);
		for (player in players) {
			var serverPlayers:Array< Player > = cast(serverSnapshot, GameWorld).getPlayers();
			var serverPlayer:Player = GameUtils.getPlayerByID(serverPlayers, player.getID());
			//trace(time + ";" + getTime());
			player.interpolate(deltaTime, serverPlayer, serverSnapshot.getTime() - getTime() + deltaTime);
		}
		*/
    }
	
	public override function extrapolate(deltaTime:Int):Void {
		super.extrapolate(deltaTime);
		
		//trace("EXTRAPOLATE");
		//var player:Player = players[0];
		//trace("PLAYER BEFORE" + player.getY());
		/*
		super.extrapolate(deltaTime);
		physicsWorld.update(deltaTime);
		*/
		//trace("AFTER " + player.getY());
		if ( physicsWorld != null )
			physicsWorld.update(deltaTime);
    }
	
    public override function synchronize(serverSnapshot:ISnapshot):Void {
		//trace("SYNC" + serverSnapshot.getTime());
		var serverGameWorld:GameWorld = cast(serverSnapshot, GameWorld);
		var serverPlayersCopy = GameUtils.copyPlayers(serverGameWorld.getPlayers());
        var playersToRemove:Array< Player > = new Array< Player >();
        for (player in players) {
            var serverPlayer = GameUtils.getPlayerByID(serverPlayersCopy, player.getID());
            if (serverPlayer == null) {
                playersToRemove.push(player);
            } else {
                serverPlayersCopy.remove(serverPlayer);
                player.synchronize(serverPlayer);
            }
        }
		
        for (player in playersToRemove) { 
            gameEventDispatcher.notifyListeners(playerRemoved, player);
			players.remove(player);
		}
		
        for (player in serverPlayersCopy) {
            gameEventDispatcher.notifyListeners(playerAdded, player);
            players.push(player);
			physicsWorld.addCircle(player.getCircle());
        }
    }
	
	public override function getGameObject(id:Int):IGameObject {
		for ( player in players ) {
			if ( player != null && player.getID() == id ) 
				return player;
		}
		
		return null;
	}
	
	public override function getAllGameObjects():List<IGameObject> {
		var gameObjects = new List<IGameObject>();
		for ( player in players )
			gameObjects.push(player);
		
		return gameObjects;
	}	
}    
